#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：python_learning 
@File ：download_ftp_data.py
@IDE  ：PyCharm 
@Author ：李涵彬
@Date ：2024/6/19 下午4:04 
"""

import os
import re
import sys
import datetime, time
from ftplib import FTP  # 定义了FTP类，实现ftp上传和下载
import traceback
import logging

LOG_FORMAT = "%(message)s"  # "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置输出日志格式
DATE_FORMAT = '%Y-%m-%d  %H:%M:%S %a '  # 配置输出时间的格式，注意月份和天数不要搞乱了
LOG_PATH = None  # os.path.join(os.getcwd(),'./logs/ftpget.log')
logging.basicConfig(level=logging.DEBUG,
					format=LOG_FORMAT,
					datefmt=DATE_FORMAT,
					filemode='a',  # 覆盖之前的记录 'a'是追加
					filename=LOG_PATH  # 有了filename参数就不会直接输出显示到控制台，而是直接写入文件
					)

FTP_PERFECT_BUFF_SIZE = 8192

'''
@检查是否下载完整
'''


def is_same_size(ftp, local_file, remote_file):
	"""判断远程文件和本地文件大小是否一致

	   参数:
		 local_file: 本地文件
		 remote_file: 远程文件
	"""
	try:
		remote_file_size = ftp.size(remote_file)
	except Exception as err:
		logging.debug("get remote file_size failed, Err:%s" % err)
		remote_file_size = -1

	try:
		local_file_size = os.path.getsize(local_file)
	except Exception as err:
		logging.debug("get local file_size failed, Err:%s" % err)
		local_file_size = -1

	# 三目运算符
	result = True if (remote_file_size == local_file_size) else False

	logging.debug('Download 【%s】 %s , remote_file_size = %d, local_file_size = %d.' % (
		remote_file, 'success' if (result == True) else 'failed', remote_file_size, local_file_size))
	return result


'''
@实际负责下载功能的函数
'''


def ftp_download(local_file, remote_file, ftp):
	# 缓冲器大小给8k
	global FTP_PERFECT_BUFF_SIZE
	buffsize = FTP_PERFECT_BUFF_SIZE

	# 本地是否有此文件
	if not os.path.exists(local_file):
		with open(local_file, 'wb') as f:
			ftp.retrbinary('RETR %s' % remote_file, f.write, buffsize)
		# ftp.set_debuglevel(0)             #关闭调试模式

		# 到这里文件会写入关闭，放在with语句外面
		return is_same_size(ftp, local_file, remote_file)
	else:
		if not is_same_size(ftp, local_file, remote_file):
			# 如果已存在，但是不完整，重新写入覆盖
			with open(local_file, 'wb+') as f:
				ftp.retrbinary('RETR %s' % remote_file, f.write, buffsize)

			# 到这里文件会写入关闭，放在with语句外面
			return is_same_size(ftp, local_file, remote_file)
		else:
			print('【%s】 is exists in local path ... pass ...' % (remote_file))
			return True


"""
# 根据文件名前缀下载文件
"""


def DownLoadRUledFile(local_dir, remote_dir, filename, ftp):
	print("remote_dir:", remote_dir)

	if not os.path.exists(local_dir):
		os.makedirs(local_dir)
	local_file = os.path.join(local_dir, filename)  # 下载到当地的全路径

	try:
		# 打开该远程目录
		ftp.cwd(remote_dir)
		# 直接下载
		ftp.voidcmd('TYPE I')  # 将传输模式改为二进制模式 ,避免提示 ftplib.error_perm: 550 SIZE not allowed in ASCII
		ftp_download(local_file, filename, ftp)
	except:
		print('some error happend in get file:%s. Err:%s' % (filename, traceback.format_exc()))
		logging.debug('some error happend in get file:%s. Err:%s' % (filename, traceback.format_exc()))

	return


"""
下载整个目录下的文件
"""


def DownLoadFileTree(local_dir, remote_dir, ftp, IsRecursively=False):
	print("remote_dir:", remote_dir)

	if not os.path.exists(local_dir):
		print('local directory %s not exists , make it ...')
		os.makedirs(local_dir)

	# 打开该远程目录
	ftp.cwd(remote_dir)
	dir_list = []
	''' 对当前目录进行dir 将结果放入列表'''
	ftp.dir('.', dir_list.append)
	for dif in dir_list:
		if dif.startswith("d"):
			if IsRecursively:
				''' 该对象为目录 递归下载'''
				print('【%s】 is a directory, download it Recursively...' % (dif))
				p_subdir = dif.split(" ")[-1]
				p_local_subdir = os.path.join(local_dir, p_subdir)
				''' 本地子目录创建原理相同 但不在此处创建 在递归出创建'''
				p_remote_subdir = os.path.join(ftp.pwd(), p_subdir)
				DownLoadFileTree(p_local_subdir, p_remote_subdir, ftp, IsRecursively)
				ftp.cwd("..")  # 返回上层目录
			else:
				print('【%s】 is a directory, download mode is UnRecursive, continue...' % (dif))
				continue
		else:
			''' 是文件 直接下载 '''
			print('【%s】 is a file, download it directly...' % (dif))
			remote_file = dif.split(" ")[-1]
			local_lfile = os.path.join(local_dir, remote_file)  # 下载到当地的全路径
			ftp_download(local_lfile, remote_file, ftp)

	return


if __name__ == '__main__':
	host = '1.2.3.4'
	port = 21
	username = 'li'
	password = 'ly'
	ftp = FTP()
	ftp.connect(host, port)
	ftp.login(username, password)

	local_dir = os.getcwd()
	remote_dir = 'lily/'

	# filename = '12345.txt'
	''' 按文件名下载 '''
	# DownLoadRUledFile(local_dir, remote_dir, filename, ftp)
	''' 递归下载整个目录 '''
	IsRecursively = True  # 是否递归目录下的子目录 开关 是 True 否 False
	DownLoadFileTree(local_dir, remote_dir, ftp, IsRecursively)
